package com.aispeech.asr.apis.ssc.data.domain;

import java.time.Instant;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.bson.types.ObjectId;
import org.springframework.data.mongodb.core.mapping.Document;
import org.springframework.data.mongodb.core.mapping.MongoId;

import com.aispeech.asr.comm.constants.Progress;
import com.aispeech.asr.comm.data.vo.Result;
import com.aispeech.asr.comm.enums.ErrorCode;
import com.aispeech.asr.comm.utils.BeanUtils;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
import com.fasterxml.jackson.databind.annotation.JsonNaming;

import lombok.ToString;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@ToString
@Document("asr_ssc_tasks_v1")
@JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy.class)
public final class TaskDoc {
    int progress;
    List<Map<String, Object>> result;
    @JsonInclude(JsonInclude.Include.NON_NULL)
    List<Align> aligns;
    List<VprAudioInfo> prepareAudioInfos;
    @MongoId
    private String id;
    private String productId;
    @JsonInclude(JsonInclude.Include.NON_NULL)
    private int priority = 0;
    private String hostname = null;
    private long update_t;
    @JsonIgnoreProperties
    private Instant finished_t;
    private Map<String, Object> request;
    @JsonInclude(JsonInclude.Include.NON_NULL)
    private Map<String, Long> metrics;
    @JsonInclude(JsonInclude.Include.NON_NULL)
    private Map<String, Object> error;
    @JsonInclude(JsonInclude.Include.NON_NULL)
    private String parentId;
    private String res;
    private String resVersion;
    public TaskDoc() {
        metrics = new HashMap<String, Long>() {{
            put("received_t", System.currentTimeMillis());
        }};
        result = new ArrayList<>();
    }

    public static TaskDoc of(String productId, Map<String, Object> request) {
        TaskDoc task = new TaskDoc();
        task.setId(new ObjectId().toString());
        task.setProductId(productId);
        task.setProgress(Progress.IDLE);
        task.setRequest(request);

        return task;
    }

    public static Result mergeAnnotation(TaskDoc taskDoc) {
    	
    	Map<String, Object> errorMap = taskDoc.getError();
    	if(errorMap != null && errorMap.size()>0 && !"0".equals(errorMap.get("errid").toString()) ) {
    		
    		return Result.fail(Integer.valueOf(errorMap.get("errid").toString()), errorMap.get("error").toString());
    	}
    	
    	
//        if ((int) taskDoc.getRequest().getOrDefault("debug", 0) != 1) {
//            
//            List<Map<String, Object>> results = taskDoc.getResult();
//            for (int i = 0; i < results.size(); i++) {
//                Map<String, Object> row = results.get(i);
//                row.remove("speaker_ssc");
//            }
//            taskDoc.setResult(results);
//        }
//        
//        if ((int) taskDoc.getRequest().getOrDefault("useMetrics", 0) != 1) {
//            taskDoc.setMetrics(null);
//        }

        taskDoc.setParentId(null);
        //taskDoc.setError(null);

        Map<String, Object> req = new HashMap<>();
        taskDoc.getRequest().forEach((key, value) -> {
            if (!("debug".equals(key) || "useMetrics".equals(key))) {
                req.put(BeanUtils.humpToSnake(key), value);
            }
        });

        taskDoc.setRequest(req);

        return Result.ok(taskDoc);
    }

    
    public List<Align> getAligns() {
        return aligns;
    }

    public void setAligns(List<Align> aligns) {
        this.aligns = aligns;
    }
    
    public List<VprAudioInfo> getPrepareAudioInfos() {
        return prepareAudioInfos;
    }

    public void setPrepareAudioInfos(List<VprAudioInfo> prepareAudioInfos) {
        this.prepareAudioInfos = prepareAudioInfos;
    }

    public Instant getFinished_t() {
        return finished_t;
    }

    public void setFinished_t(Instant finished_t) {
        this.finished_t = finished_t;
    }

    public String getRes() {
        return res;
    }

    public void setRes(String res) {
        this.res = res;
    }

    public String getResVersion() {
        return resVersion;
    }

    public void setResVersion(String resVersion) {
        this.resVersion = resVersion;
    }

    public String getParentId() {
        return parentId;
    }

    public void setParentId(String parentId) {
        this.parentId = parentId;
    }


    public String getProductId() {
        return productId;
    }

    public void setProductId(String productId) {
        this.productId = productId;
    }

    public int getProgress() {
        return progress;
    }

    public void setProgress(int progress) {
        this.progress = progress;
    }

    public List<Map<String, Object>> getResult() {
        return result;
    }

    public void setResult(List<Map<String, Object>> result) {
        this.result = result;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public int getPriority() {
        return priority;
    }

    public void setPriority(int priority) {
        this.priority = priority;
    }

    public String getHostname() {
        return hostname;
    }

    public void setHostname(String hostname) {
        this.hostname = hostname;
    }

    public long getUpdate_t() {
        return update_t;
    }

    public void setUpdate_t(long update_t) {
        this.update_t = update_t;
    }

    public Map<String, Object> getRequest() {
        return request;
    }

    public void setRequest(Map<String, Object> request) {
        this.request = request;
        String appId = (String) request.get("appId");

        if (StringUtils.isNotEmpty(appId))
            productId = appId;
    }

    public Map<String, Long> getMetrics() {
        return metrics;
    }

    public void setMetrics(Map<String, Long> metrics) {
        this.metrics = metrics;
    }

    public void addMetric(String type) {
        if (metrics == null) {
            metrics = new HashMap<>();
        }

        metrics.put(type, System.currentTimeMillis());
    }

    public void addMetric(String type, long ts) {
        if (metrics == null) {
            metrics = new HashMap<>();
        }

        metrics.put(type, ts);
    }

    public Map<String, Object> getError() {
        return error;
    }

    public void setError(Map<String, Object> error) {
        this.error = error;
    }

    public void updateError(ErrorCode code) {
        updateError(code.errid, code.error);
    }

    public void updateError(int code, String message) {
        if (error == null)
            error = new HashMap<>();

        error.put("code", code);
        error.put("message", message);
    }

}
